package com.xiashitech.apiservice.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.xiashitech.apiservice.Constants.DBType;
import com.xiashitech.apiservice.Constants.ErrorCode;
import com.xiashitech.apiservice.Constants.Operate;
import com.xiashitech.apiservice.allmem.DbMemManager;
import com.xiashitech.apiservice.config.AuthConfig;
import com.xiashitech.apiservice.dao.PassappMapper;
import com.xiashitech.apiservice.dao.model.Passapp;
import com.xiashitech.apiservice.dto.*;
import com.xiashitech.apiservice.service.IAuthFactService;
import com.xiashitech.apiservice.service.IUserInfoService;
import com.xiashitech.apiservice.util.BeanCopierUtil;
import com.xiashitech.interfaces.agent.dto.SystemInfoDTO;
import com.xiashitech.interfaces.apiservice.dto.base.AuthDesenseAction;
import com.xiashitech.interfaces.apiservice.dto.base.Column;
import com.xiashitech.interfaces.apiservice.dto.base.Table;
import com.xiashitech.interfaces.authservice.AuthService;
import com.xiashitech.interfaces.authservice.dto.AuthDTO;
import com.xiashitech.interfaces.sqlparser.SqlParser;
import com.xiashitech.interfaces.sqlparser.dto.ResultDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.lang.System;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor(onConstructor =@_(@Autowired))
public class AuthFactServiceImpl implements IAuthFactService {
    private static final Log log = LogFactory.get();
    private final SqlParser sqlParser;

    private final AuthService authService;

    private final IUserInfoService authFactService;

    private final PassappMapper passappMapper;

    private final AuthConfig authConfig;

    private static String apiServiceName;

    private static final String COMMA = ",";

    private static final String DOT = ".";

    private static Set<String> shippingPortCache = new HashSet();

    private final DbMemManager dbMemManager;

    @Cacheable(value="supplementUserTracing", key="#authFactDTO.userId+'-'+#authFactDTO.sql", sync = true)
    @Override
    public AuthFactDTO supplementUserTracing(AuthFactDTO authFactDTO) {
        final AuthFactDTO finalAuthFactDTO = BeanCopierUtil.copy(authFactDTO,AuthFactDTO.class);
        //sql解析结果
        ResultDTO resultDTO = ResultDTO.builder().build();
        /**
         * sql解析
         */
        try {
            resultDTO = sqlParser.find(finalAuthFactDTO.getSql());
            finalAuthFactDTO.setOperate(resultDTO.getSqlType());
        } catch (Exception e) {
//            log.error(ErrorCode.RESULT_4003.getMessage());
//            log.error("Incorrectly parsed sql:"+finalAuthFactDTO.getSql());
//            log.error(e);
            return AuthFactDTO.builder()
                    .operate(resultDTO.getSqlType())
                    .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                    .code(ErrorCode.RESULT_4003.getCode())
                    .message(ErrorCode.RESULT_4003.getMessage()+":"+e.toString()).build();
        }
        /**
         * 关键信息校验
         */
        if (resultDTO.getTableFinderDTOS().size() == 0 && resultDTO.getColumnRelationDTOS().size() == 0) {
            return AuthFactDTO.builder()
                    .operate(resultDTO.getSqlType())
                    .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                    .code(ErrorCode.RESULT_4004.getCode())
                    .message(ErrorCode.RESULT_4004.getMessage()).build();
        }
        if(finalAuthFactDTO.getSchema() == null || "".equals(finalAuthFactDTO.getSchema())) {
            return AuthFactDTO.builder()
                    .operate(resultDTO.getSqlType())
                    .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                    .code(ErrorCode.RESULT_4005.getCode())
                    .message(ErrorCode.RESULT_4005.getMessage()).build();
        }
//        int a = 10;
//        if(a == 10) {
//            return AuthFactDTO.builder()
//                    .operate(resultDTO.getSqlType())
//                    .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
//                    .code(ErrorCode.RESULT_4016.getCode())
//                    .message(ErrorCode.RESULT_4016.getMessage()).build();
//        }
        /**
         * 通过调用openmetadata进行表信息补全：1、校验列和表的所属关系；2、补全tag信息
         */
        try {
            String dbService = HttpUtil.createGet(authConfig.getMetaDataUrlForDBService()).execute().body();
            List<MetaDataDBService> metaDataDBServices = JSONUtil.toList(JSONUtil.parseObj(dbService).get("data").toString(), MetaDataDBService.class);
            List<MetaDataDBService> metaDataDBServicesAfterFilter = metaDataDBServices.stream().filter(metaDataDBService -> metaDataDBService.getConnection().getConfig().getHostPort().equals(finalAuthFactDTO.getIp() + ":" + finalAuthFactDTO.getPort())).collect(Collectors.toList());
            List<String> dbservices = new ArrayList();
            if(metaDataDBServicesAfterFilter.size() > 0) {
                dbservices.addAll(metaDataDBServicesAfterFilter.stream().map(metaDataDBService -> metaDataDBService.getName()).collect(Collectors.toList()));
                if(dbservices.size() > 1) {
                    List<String> dbServiceNameList = dbservices.stream().filter(dbServiceName -> dbServiceName.equals(finalAuthFactDTO.getSystemId()) || dbServiceName.contains(finalAuthFactDTO.getSystemId())).collect(Collectors.toList());
                    if(dbServiceNameList.size() == 0) {
                        return AuthFactDTO.builder()
                                .operate(resultDTO.getSqlType())
                                .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                                .code(ErrorCode.RESULT_4009.getCode())
                                .message(ErrorCode.RESULT_4009.getMessage()).build();
                    } else if (dbServiceNameList.size() == 1) {
                        dbservices = dbServiceNameList;
                    } else if (dbServiceNameList.size() > 1) {
                        List<String> descDBServiceNameList = metaDataDBServices.stream().filter(metaDataDBService -> metaDataDBService.getDescription() != null && metaDataDBService.getDescription().contains("#"+finalAuthFactDTO.getSystemId()+"#")).map(metaDataDBService -> metaDataDBService.getName()).collect(Collectors.toList());
                        if(descDBServiceNameList != null && descDBServiceNameList.size() > 0) {
                            Optional<String> dbServiceNameOptional = dbServiceNameList.stream().filter(dbServiceName -> descDBServiceNameList.contains(dbServiceName)).findFirst();
                            if(dbServiceNameOptional.isPresent()) {
                                dbservices = new ArrayList();
                                dbservices.add(dbServiceNameOptional.get());
                            } else {
                                return AuthFactDTO.builder()
                                        .operate(resultDTO.getSqlType())
                                        .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                                        .code(ErrorCode.RESULT_4009.getCode())
                                        .message(ErrorCode.RESULT_4009.getMessage()).build();
                            }
                        }
                    }
                }
            } else {
                metaDataDBServicesAfterFilter = metaDataDBServices.stream().filter(metaDataDBService -> metaDataDBService.getName().equals(finalAuthFactDTO.getSystemId())).collect(Collectors.toList());
                if(metaDataDBServicesAfterFilter.size() > 0) {
                    dbservices.addAll(metaDataDBServicesAfterFilter.stream().map(metaDataDBService -> metaDataDBService.getName()).collect(Collectors.toList()));
                } else {
                    metaDataDBServicesAfterFilter = metaDataDBServices.stream().filter(metaDataDBService -> metaDataDBService.getDescription() != null && metaDataDBService.getDescription().contains("#"+finalAuthFactDTO.getSystemId()+"#")).collect(Collectors.toList());
                    if(metaDataDBServicesAfterFilter.size() > 0) {
                        dbservices.addAll(metaDataDBServicesAfterFilter.stream().map(metaDataDBService -> metaDataDBService.getName()).collect(Collectors.toList()));
                    } else {
                        metaDataDBServicesAfterFilter = metaDataDBServices.stream().filter(metaDataDBService -> metaDataDBService.getName().contains(finalAuthFactDTO.getSystemId())).collect(Collectors.toList());
                        if(metaDataDBServicesAfterFilter.size() > 0) {
                            dbservices.addAll(metaDataDBServicesAfterFilter.stream().map(metaDataDBService -> metaDataDBService.getName()).collect(Collectors.toList()));
                        }
                    }
                }
            }

            if(dbservices.size() == 0) {
                return AuthFactDTO.builder()
                        .operate(resultDTO.getSqlType())
                        .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                        .code(ErrorCode.RESULT_4009.getCode())
                        .message(ErrorCode.RESULT_4009.getMessage()).build();
            }
            String schemas = HttpUtil.createGet(authConfig.getMetaDataUrlForDB()).execute().body();
            JSONObject jsonObject = JSONUtil.parseObj(schemas);
            List<MetaDataDB> metaDataDBS = JSONUtil.toList(jsonObject.get("data").toString(), MetaDataDB.class);
            List<String> dbservicesFinal = dbservices;
            Optional<MetaDataDB> metaDataDBOptional = metaDataDBS.stream().filter(metaDataDB -> {
                if(finalAuthFactDTO.getType().equals(DBType.Db_Type_Mysql)) {
                    if(dbservicesFinal.stream().filter(serviceName -> metaDataDB.getFullyQualifiedName().startsWith(serviceName) && metaDataDB.getName().equals(finalAuthFactDTO.getSchema())).count() > 0) {
                        return true;
                    }
                } else if(finalAuthFactDTO.getType().equals(DBType.Db_Type_Oracle)){
                    String[] fullyQualifiedName = metaDataDB.getFullyQualifiedName().split("\\.");
                    String dbName = finalAuthFactDTO.getDatabase();
                    Map<String, Map<String, String>> dbMapMap = authConfig.getOracleDbMapping();
                    if(dbMapMap != null) {
                        Map<String, String> dbMap = dbMapMap.get(finalAuthFactDTO.getSystemId());
                        if(dbMap != null) {
                            String metaDbName = dbMap.get(dbName);
                            if(metaDbName != null) {
                                dbName = metaDbName;
                            }
                        }
                    }
                    final String realDbName = dbName;
                    if(dbservicesFinal.stream().filter(serviceName -> metaDataDB.getFullyQualifiedName().startsWith(serviceName) && fullyQualifiedName[2].equals(realDbName)).count() > 0) {
                        return true;
                    }
                } else {
                    String[] fullyQualifiedName = metaDataDB.getFullyQualifiedName().split("\\.");
                    if(dbservicesFinal.stream().filter(serviceName -> metaDataDB.getFullyQualifiedName().startsWith(serviceName) && fullyQualifiedName[1].equals(finalAuthFactDTO.getDatabase())).count() > 0) {
                        return true;
                    }
                }
                return false;
            }).findFirst();
            if(metaDataDBOptional.isPresent()) {
                String[] fullyQualifiedName = metaDataDBOptional.get().getFullyQualifiedName().split("\\.");
                finalAuthFactDTO.setInstance(fullyQualifiedName[0]);
                finalAuthFactDTO.setDatabase(fullyQualifiedName[1]);
                if(authConfig.getIsAcquireMetaData()) {//获取openmetadata元数据开关
                    List<Table> tables = resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> {
                        String metaDataUrlForTable = StrUtil.format(authConfig.getMetaDataUrlForTable(), metaDataDBOptional.get().getFullyQualifiedName() + "." + tableFinderDTO.getTable());
                        String table = HttpUtil.createGet(metaDataUrlForTable).execute().body();
                        MetaDataTable metaDataTable = JSONUtil.toBean(JSONUtil.parseObj(table), MetaDataTable.class);
                        if(metaDataTable.getCode() != null && metaDataTable.getCode().equals("404")) {
                            return  Table.builder().tabName(tableFinderDTO.getTable()).tabAuth(false).build();
                        }
                        List<Column> columns = null;
                        if(tableFinderDTO.getAllColumn()) {
                            columns = metaDataTable.getColumns().stream().map(metaDataColumn -> Column.builder().colName(metaDataColumn.getName()).authDesenseActions(metaDataColumn.getEntityAuth().getAuthDesense().stream().map(authDesense -> AuthDesenseAction.builder().systemId(authDesense.getSystemName()).apiPath(authDesense.getApiPath()).patchPath(authDesense.getPatchPath()).regular(authDesense.getRegular()).isExecute(authDesense.getIsExecute()).replaceSymbol(authDesense.getReplaceSymbol()).build()).collect(Collectors.toList())).build()).collect(Collectors.toList());
                        } else {
                            columns = tableFinderDTO.getColumns().stream().filter(column -> metaDataTable.getColumns().stream().anyMatch(metaDataColumn -> metaDataColumn.getName().equals(column))).map(column -> metaDataTable.getColumns().stream().filter(metaDataColumn -> metaDataColumn.getName().equals(column)).findFirst().get()).map(metaDataColumn -> Column.builder().colName(metaDataColumn.getName()).authDesenseActions(metaDataColumn.getEntityAuth().getAuthDesense().stream().map(authDesense -> AuthDesenseAction.builder().systemId(authDesense.getSystemName()).apiPath(authDesense.getApiPath()).patchPath(authDesense.getPatchPath()).regular(authDesense.getRegular()).isExecute(authDesense.getIsExecute()).replaceSymbol(authDesense.getReplaceSymbol()).build()).collect(Collectors.toList())).build()).collect(Collectors.toList());
                        }
                        syncShippingPort(metaDataTable.getId(),finalAuthFactDTO.getApiSystemId(),finalAuthFactDTO.getApiName());
                        return  Table.builder().tabName(tableFinderDTO.getTable()).columns(columns).build();
                    }).collect(Collectors.toList());
                    finalAuthFactDTO.setTables(tables);
                }
            }
        } catch (Exception e) {
            finalAuthFactDTO.setCode(ErrorCode.RESULT_4007.getCode());
            finalAuthFactDTO.setMessage(ErrorCode.RESULT_4007.getMessage());
            finalAuthFactDTO.setTables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()));
            log.error(ErrorCode.RESULT_4007.getMessage());
            log.error(e);
            return finalAuthFactDTO;
        }

        /**
         *  调用iam拿到权限信息，按照table->column顺序获取
         */
        try {
            Passapp passapp = passappMapper.selectTokenByCode(finalAuthFactDTO.getAppCode()).stream().findFirst().orElse(Passapp.builder().build());
            if(passapp.getAuth_token() == null || "".equals(passapp.getAuth_token())) {
                return AuthFactDTO.builder()
                        .operate(resultDTO.getSqlType())
                        .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                        .code(ErrorCode.RESULT_4006.getCode())
                        .message(ErrorCode.RESULT_4006.getMessage()).build();
            }
            /**
             * 使用第三方系统用户id获取到iam系统用户id
             */
            String iamUserId = "";
            try {
                String systemId = finalAuthFactDTO.getSourceSystemId() == null ? finalAuthFactDTO.getSystemId() : finalAuthFactDTO.getSourceSystemId();
//                UserInfoResponse userInfoResponse = retrieveUserInfo.retrieveUserInfo(UserInfoRequest.builder().id(finalAuthFactDTO.getUserId()+"@"+systemId).build());
//                iamUserId = String.valueOf(userInfoResponse.getData().getId());
                iamUserId = finalAuthFactDTO.getUserId()+"@"+systemId;
            } catch (Exception e) {
                log.error(ErrorCode.RESULT_4010.getMessage());
                return AuthFactDTO.builder()
                        .operate(resultDTO.getSqlType())
                        .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                        .code(ErrorCode.RESULT_4010.getCode())
                        .message(ErrorCode.RESULT_4010.getMessage()).build();
            }
            AuthDTO authDTO = AuthDTO.builder().systemId(finalAuthFactDTO.getSystemId()).userId(iamUserId).actionId(resultDTO.getSqlType())
                    .databaseService(finalAuthFactDTO.getInstance()).databaseName(finalAuthFactDTO.getDatabase()).databaseSchema(finalAuthFactDTO.getSchema())
                    .appCode(finalAuthFactDTO.getAppCode()).appSecret(passapp.getAuth_token()).iamBaseUrl(authConfig.getIamBaseUrl()).build();
            /**
             * 获取表、列的权限
             */
            String sqlType = resultDTO.getSqlType();
            finalAuthFactDTO.getTables().stream().forEach(table -> {
                authDTO.setTableName(table.getTabName());
                //获取表权限
                AuthDTO tabAuthResult = authService.verifyAuth(authDTO);
                table.setTabAuth(tabAuthResult.isAuth());
                table.setTabAuthReason(tabAuthResult.getResult());
                //获取列权限
                if(table.getColumns() != null) {
                    table.getColumns().stream().forEach(column -> {
                        authDTO.setColumnName(column.getColName());
                        //获取列权限
                        if(Operate.INSERT.name().equals(sqlType) || Operate.DELETE.name().equals(sqlType)) {
                            return;
                        }
                        AuthDTO colAuthResult = authService.verifyAuth(authDTO);
                        column.setColAuth(colAuthResult.isAuth());
                        column.setColAuthReason(colAuthResult.getResult());
                    });
                }
                authDTO.setTableName(null);
                authDTO.setColumnName(null);
            });
        } catch (Exception e) {
            finalAuthFactDTO.setCode(ErrorCode.RESULT_4008.getCode());
            finalAuthFactDTO.setMessage(ErrorCode.RESULT_4008.getMessage());
            finalAuthFactDTO.setTables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()));
            log.error(ErrorCode.RESULT_4008.getMessage());
            log.error(e);
        }
        return finalAuthFactDTO;
    }


    @Cacheable(value="supplementUserTracing", key="#authFactDTO.userId+'-'+#authFactDTO.sql", sync = true)
    @Override
    public AuthFactDTO supplementUserTracingCache(AuthFactDTO authFactDTO) {
        final AuthFactDTO finalAuthFactDTO = BeanCopierUtil.copy(authFactDTO,AuthFactDTO.class);
        log.info("supplementUserTracingCache enter: {}, {}, {}, {}, {}" , finalAuthFactDTO.getSystemId(), finalAuthFactDTO.getUserId(),finalAuthFactDTO.getInstance(), finalAuthFactDTO.getDatabase(), finalAuthFactDTO.getSchema());
        // mysql:  supplementUserTracingCache enter: soc, ex_chenrg, null, null, pcsa_soc
        // oracle: supplementUserTracingCache enter: cw-icip, 532, null, fpsdbt1, null
        //sql解析结果
        ResultDTO resultDTO = ResultDTO.builder().build();
        /**
         * sql解析
         */
        try {
            resultDTO = sqlParser.find(finalAuthFactDTO.getSql());
            finalAuthFactDTO.setOperate(resultDTO.getSqlType());
        } catch (Exception e) {
            return AuthFactDTO.builder()
                    .operate(resultDTO.getSqlType())
                    .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                    .code(ErrorCode.RESULT_4003.getCode())
                    .message(ErrorCode.RESULT_4003.getMessage()+":"+e.toString()).build();
        }
        /**
         * 关键信息校验
         */
        if (resultDTO.getTableFinderDTOS().size() == 0 && resultDTO.getColumnRelationDTOS().size() == 0) {
            return AuthFactDTO.builder()
                    .operate(resultDTO.getSqlType())
                    .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                    .code(ErrorCode.RESULT_4004.getCode())
                    .message(ErrorCode.RESULT_4004.getMessage()).build();
        }
        if(finalAuthFactDTO.getType().equalsIgnoreCase(DBType.Db_Type_Mysql) && (finalAuthFactDTO.getSchema() == null || "".equals(finalAuthFactDTO.getSchema()))) {
            return AuthFactDTO.builder()
                    .operate(resultDTO.getSqlType())
                    .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                    .code(ErrorCode.RESULT_4005.getCode())
                    .message(ErrorCode.RESULT_4005.getMessage()).build();
        } else if(finalAuthFactDTO.getType().equalsIgnoreCase(DBType.Db_Type_Oracle) && (finalAuthFactDTO.getDatabase() == null || "".equals(finalAuthFactDTO.getDatabase()))) {
            return AuthFactDTO.builder()
                    .operate(resultDTO.getSqlType())
                    .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                    .code(ErrorCode.RESULT_4005.getCode())
                    .message(ErrorCode.RESULT_4005.getMessage()).build();
        }
        log.info("supplementUserTracingCache after sqlParsed: {}, {}, {}" , finalAuthFactDTO.getSystemId(), resultDTO.getSqlType(), resultDTO.getTableFinderDTOS());
        /**
         * 通过调用openmetadata进行表信息补全：1、校验列和表的所属关系；2、补全tag信息
         */
        try {
            List<MetaDataDBService> metaDataDBServices = dbMemManager.getDbInfoInMemory().getMetaDataDBServices();
            List<MetaDataDBService> metaDataDBServicesAfterFilter = metaDataDBServices.stream().filter(metaDataDBService -> metaDataDBService.getConnection().getConfig().getHostPort().equals(finalAuthFactDTO.getIp() + ":" + finalAuthFactDTO.getPort())).collect(Collectors.toList());
            List<String> dbservices = new ArrayList();
            if(metaDataDBServicesAfterFilter.size() > 0) {
                dbservices.addAll(metaDataDBServicesAfterFilter.stream().map(metaDataDBService -> metaDataDBService.getName()).collect(Collectors.toList()));
                if(dbservices.size() > 1) {
                    List<String> dbServiceNameList = dbservices.stream().filter(dbServiceName -> dbServiceName.equals(finalAuthFactDTO.getSystemId()) || dbServiceName.contains(finalAuthFactDTO.getSystemId())).collect(Collectors.toList());
                    if(dbServiceNameList.size() == 0) {
                        return AuthFactDTO.builder()
                                .operate(resultDTO.getSqlType())
                                .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                                .code(ErrorCode.RESULT_4009.getCode())
                                .message(ErrorCode.RESULT_4009.getMessage()).build();
                    } else if (dbServiceNameList.size() == 1) {
                        dbservices = dbServiceNameList;
                    } else if (dbServiceNameList.size() > 1) {
                        List<String> descDBServiceNameList = metaDataDBServices.stream().filter(metaDataDBService -> metaDataDBService.getDescription() != null && metaDataDBService.getDescription().contains("#"+finalAuthFactDTO.getSystemId()+"#")).map(metaDataDBService -> metaDataDBService.getName()).collect(Collectors.toList());
                        if(descDBServiceNameList != null && descDBServiceNameList.size() > 0) {
                            Optional<String> dbServiceNameOptional = dbServiceNameList.stream().filter(dbServiceName -> descDBServiceNameList.contains(dbServiceName)).findFirst();
                            if(dbServiceNameOptional.isPresent()) {
                                dbservices = new ArrayList();
                                dbservices.add(dbServiceNameOptional.get());
                            } else {
                                return AuthFactDTO.builder()
                                        .operate(resultDTO.getSqlType())
                                        .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                                        .code(ErrorCode.RESULT_4009.getCode())
                                        .message(ErrorCode.RESULT_4009.getMessage()).build();
                            }
                        }
                    }
                }
            } else {
                metaDataDBServicesAfterFilter = metaDataDBServices.stream().filter(metaDataDBService -> metaDataDBService.getName().equals(finalAuthFactDTO.getSystemId())).collect(Collectors.toList());
                if(metaDataDBServicesAfterFilter.size() > 0) {
                    dbservices.addAll(metaDataDBServicesAfterFilter.stream().map(metaDataDBService -> metaDataDBService.getName()).collect(Collectors.toList()));
                } else {
                    metaDataDBServicesAfterFilter = metaDataDBServices.stream().filter(metaDataDBService -> metaDataDBService.getDescription() != null && metaDataDBService.getDescription().contains("#"+finalAuthFactDTO.getSystemId()+"#")).collect(Collectors.toList());
                    if(metaDataDBServicesAfterFilter.size() > 0) {
                        dbservices.addAll(metaDataDBServicesAfterFilter.stream().map(metaDataDBService -> metaDataDBService.getName()).collect(Collectors.toList()));
                    } else {
                        metaDataDBServicesAfterFilter = metaDataDBServices.stream().filter(metaDataDBService -> metaDataDBService.getName().contains(finalAuthFactDTO.getSystemId())).collect(Collectors.toList());
                        if(metaDataDBServicesAfterFilter.size() > 0) {
                            dbservices.addAll(metaDataDBServicesAfterFilter.stream().map(metaDataDBService -> metaDataDBService.getName()).collect(Collectors.toList()));
                        }
                    }
                }
            }

            if(dbservices.size() == 0) {
                return AuthFactDTO.builder()
                        .operate(resultDTO.getSqlType())
                        .tables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()))
                        .code(ErrorCode.RESULT_4009.getCode())
                        .message(ErrorCode.RESULT_4009.getMessage()).build();
            }
            log.info("supplementUserTracingCache after dbservice: {}, {}" , finalAuthFactDTO.getSystemId(), dbservices);
            List<MetaDataDB> metaDataDBS = dbMemManager.getDbInfoInMemory().getMetaDataDBS();//JSONUtil.toList(jsonObject.get("data").toString(), MetaDataDB.class);
            List<String> dbservicesFinal = dbservices;
            Optional<MetaDataDB> metaDataDBOptional = metaDataDBS.stream().filter(metaDataDB -> {
                if(finalAuthFactDTO.getType().equals(DBType.Db_Type_Mysql)) {
                    if(dbservicesFinal.stream().filter(serviceName -> metaDataDB.getFullyQualifiedName().startsWith(serviceName)).count() > 0 && metaDataDB.getName().equals(finalAuthFactDTO.getSchema())) {
                        return true;
                    }
                } else if(finalAuthFactDTO.getType().equals(DBType.Db_Type_Oracle)){
                    String[] fullyQualifiedName = metaDataDB.getFullyQualifiedName().split("\\.");
                    String dbName = finalAuthFactDTO.getDatabase();
                    Map<String, Map<String, String>> dbMapMap = authConfig.getOracleDbMapping();
                    if(dbMapMap != null) {
                        Map<String, String> dbMap = dbMapMap.get(finalAuthFactDTO.getSystemId());
                        if(dbMap != null) {
                            String metaDbName = dbMap.get(dbName);
                            if(metaDbName != null) {
                                dbName = metaDbName;
                            }
                        }
                    }
                    if(dbservicesFinal.stream().filter(serviceName -> metaDataDB.getFullyQualifiedName().startsWith(serviceName) ).count() > 0 && fullyQualifiedName[2].equals(dbName)) {
                        return true;
                    }
                } else if(finalAuthFactDTO.getType().equals(DBType.Db_Type_Oracle)){
                    String[] fullyQualifiedName = metaDataDB.getFullyQualifiedName().split("\\.");
                    String dbName = finalAuthFactDTO.getDatabase();
                    Map<String, Map<String, String>> dbMapMap = authConfig.getOracleDbMapping();
                    if(dbMapMap != null) {
                        Map<String, String> dbMap = dbMapMap.get(finalAuthFactDTO.getSystemId());
                        if(dbMap != null) {
                            String metaDbName = dbMap.get(dbName);
                            if(metaDbName != null) {
                                dbName = metaDbName;
                            }
                        }
                    }
                    if(dbservicesFinal.stream().filter(serviceName -> metaDataDB.getFullyQualifiedName().startsWith(serviceName) ).count() > 0 && fullyQualifiedName[2].equals(dbName)) {
                        return true;
                    }
                } else {
                    String[] fullyQualifiedName = metaDataDB.getFullyQualifiedName().split("\\.");
                    // TODO 以下应该是错误的
                    if(dbservicesFinal.stream().filter(serviceName -> metaDataDB.getFullyQualifiedName().startsWith(serviceName) && metaDataDB.getName().equals(fullyQualifiedName[1].equals(finalAuthFactDTO.getDatabase()))).count() > 0) {
                        return true;
                    }
                }
                return false;
            }).findFirst();
            log.info("supplementUserTracingCache after metaDataDBS: {}, {}" , finalAuthFactDTO.getSystemId(), metaDataDBOptional.isPresent());
            if(metaDataDBOptional.isPresent()) {
                String[] fullyQualifiedName = metaDataDBOptional.get().getFullyQualifiedName().split("\\.");
                log.info("supplementUserTracingCache exist metaDataDBS, the fullyQualifiedName: {}" , metaDataDBOptional.get().getFullyQualifiedName());
                if(authConfig.getIsAcquireMetaData()) {//获取openmetadata元数据开关
                    String fullyQualifiedNameStr = metaDataDBOptional.get().getFullyQualifiedName();
                    // TODO 针对不同类型的数据库，key 的一致系性待验证
                    String keyTmp = finalAuthFactDTO.getSystemId() + "." + fullyQualifiedName[0] + "." + metaDataDBOptional.get().getName();
                    if(finalAuthFactDTO.getType().equals(DBType.Db_Type_Mysql)) {
                        // "instance":"jsh-erp","database":"default","schema":"jsh_erp"
                        keyTmp = finalAuthFactDTO.getSystemId() + "." + fullyQualifiedName[0] + "." +  finalAuthFactDTO.getSchema();//finalAuthFactDTO.getDatabase();
                    } else if(finalAuthFactDTO.getType().equals(DBType.Db_Type_Oracle)) {
                        // "instance":"null","database":"fpsdbt1","schema":"null"
                        String dbName = finalAuthFactDTO.getDatabase();
                        Map<String, Map<String, String>> dbMapMap = authConfig.getOracleDbMapping();
                        if(dbMapMap != null) {
                            Map<String, String> dbMap = dbMapMap.get(finalAuthFactDTO.getSystemId());
                            if(dbMap != null) {
                                String metaDbName = dbMap.get(dbName);
                                if(metaDbName != null) {
                                    dbName = metaDbName;
                                }
                            }
                        }
                        keyTmp = finalAuthFactDTO.getSystemId() + "." + fullyQualifiedName[0] + "." +  dbName;//finalAuthFactDTO.getDatabase();
                    }
                    String keyPart = keyTmp;
                    String operator = resultDTO.getSqlType();
                    Map<String, Table> keyMap = resultDTO.getTableFinderDTOS().stream().map(tableRequestDTO->{
                        Table table = Table.builder().tabName(tableRequestDTO.getTable()).columns(tableRequestDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableRequestDTO.getAllColumn()).build();
                        String cacheKey = keyPart + "." + finalAuthFactDTO.getUserId() + "." + tableRequestDTO.getTable() + "." + operator;
                        log.info("supplementUserTracingCache key: {}", cacheKey);
                        return new AbstractMap.SimpleEntry<>(cacheKey, table);
                    }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
                    List<Table> tables = keyMap.entrySet().stream().map(entry->{
                        String key = entry.getKey();
                        Table table = dbMemManager.getDbInfoInMemory().getUserAuthTableMap().get(key);
                        if(table != null) {
                            System.out.println("tableIdKey: " + (fullyQualifiedNameStr + "." + table.getTabName()) + ":" + dbMemManager.getDbInfoInMemory().getTableIdMap().get(fullyQualifiedNameStr + "." + table.getTabName()));
                            syncShippingPort(dbMemManager.getDbInfoInMemory().getTableIdMap().get(fullyQualifiedNameStr + "." + table.getTabName()), finalAuthFactDTO.getApiSystemId(), finalAuthFactDTO.getApiName());
                        } else {
                            log.info("supplementUserTracingCache has no key：{}", key);
                            table = entry.getValue();
                        }
                        return table;
                    }).collect(Collectors.toList());
                    finalAuthFactDTO.setTables(tables);
                }
            }
        } catch (Exception e) {
            finalAuthFactDTO.setCode(ErrorCode.RESULT_4007.getCode());
            finalAuthFactDTO.setMessage(ErrorCode.RESULT_4007.getMessage());
            finalAuthFactDTO.setTables(resultDTO.getTableFinderDTOS() == null ? null : resultDTO.getTableFinderDTOS().stream().map(tableFinderDTO -> Table.builder().tabName(tableFinderDTO.getTable()).columns(tableFinderDTO.getColumns().stream().map(column -> Column.builder().colName(column).build()).collect(Collectors.toList())).allColumn(tableFinderDTO.getAllColumn()).build()).collect(Collectors.toList()));
            log.error(ErrorCode.RESULT_4007.getMessage());
            log.error(e);
            return finalAuthFactDTO;
        }
        return finalAuthFactDTO;
    }

    public AuthFactDTO getSystemInfo(AuthFactDTO authFactDTO) {
        Passapp passapp = passappMapper.selectTokenByCode(authFactDTO.getAppCode()).stream().findFirst().orElse(Passapp.builder().build());
        if(passapp.getAuth_token() == null || "".equals(passapp.getAuth_token())) {
            return AuthFactDTO.builder()
                    .systemInfoDTO(SystemInfoDTO.builder().systemExist(Boolean.FALSE).build())
                    .code(ErrorCode.RESULT_4006.getCode())
                    .message(ErrorCode.RESULT_4006.getMessage()).build();
        }
        SystemInfoDTO systemInfoDTO = SystemInfoDTO.builder().build();
        try {
            String systemInfo = HttpUtil.createGet(authConfig.getSystemInfoUrl()+authFactDTO.getSystemId())
                    .header("X-BK-APP-CODE",authFactDTO.getAppCode())
                    .header("X-BK-APP-SECRET",passapp.getAuth_token())
                    .execute().body();
            JSONObject jsonObject = JSONUtil.parseObj(systemInfo);
            if(jsonObject.getInt("code") == 0) {
                systemInfoDTO = JSONUtil.toBean((JSONObject)jsonObject.get("data"),SystemInfoDTO.class);
                systemInfoDTO.setSystemExist(Boolean.TRUE);
            } else {
                systemInfoDTO.setSystemExist(Boolean.FALSE);
            }
        } catch (Exception e) {
            systemInfoDTO.setSystemExist(Boolean.FALSE);
            log.error(ErrorCode.RESULT_4011.getMessage());
            log.error(e);
            return AuthFactDTO.builder()
                    .systemInfoDTO(systemInfoDTO)
                    .code(ErrorCode.RESULT_4011.getCode())
                    .message(ErrorCode.RESULT_4011.getMessage()).build();
        }
        return AuthFactDTO.builder().systemInfoDTO(systemInfoDTO).build();
    }

    /**
     * 同步入口api到数据库表的数据出口实体
     * @param tableId
     * @param apiSystemId
     * @param apiName
     */
    private void syncShippingPort(String tableId, String apiSystemId, String apiName) {
        if(tableId == null || apiSystemId == null || apiName == null) {
            return;
        }
        if(apiServiceName == null) {
            List<ApiService> apiServices = getApiServices();
            ApiService apiService;
            if (apiServices != null && apiServices.size() > 0) {
                apiService = apiServices.get(0);
                apiServiceName = apiService.getName();
            } else {
                return;
            }
        }
        TableShippingPort tableShippingPort = TableShippingPort.builder().apiSet(Arrays.asList(apiName.split(COMMA)).stream().map(apiNameOriginal -> apiServiceName + DOT + apiSystemId + DOT + apiNameOriginal.replace("/", "_")).collect(Collectors.toList())).build();
        if(shippingPortCache.contains(tableId + DOT + apiSystemId + DOT + apiName)) {
           return;
        }
        new Thread(() -> {
            try {
                HttpResponse httpResponse = HttpRequest.put(StrUtil.format(authConfig.getMetaDataUrlForTableShippingPort(), tableId))
                        .body(JSONUtil.toJsonStr(tableShippingPort),"application/json")
                        .timeout(30 * 1000)
                        .execute();
                if(!(httpResponse.isOk() && JSONUtil.isTypeJSON(httpResponse.body()))) {
                    log.error("the shippingPort{} is not updated for the tableId{}",tableShippingPort.getApiSet(),tableId);
                } else {
                    shippingPortCache.add(tableId + DOT + apiSystemId + DOT + apiName);
                }
            } catch (Exception e) {
                log.error(ErrorCode.RESULT_4018.getMessage());
                log.error(e);
            }
        }).start();
    }

    private List<ApiService> getApiServices() {
        try {
            String apiServiceJsons = HttpUtil.createGet(authConfig.getApiUrlForListApiServices()).contentType("application/json").execute().body();
            JSONObject jsonObject = JSONUtil.parseObj(apiServiceJsons);
            return JSONUtil.toList(jsonObject.get("data").toString(), ApiService.class);
        } catch (Exception e) {
            log.error(e);
        }
        return new ArrayList();
    }
}
